function varargout = TLDiscreteStateSpaceDlg(action,varargin)

% TL_DISCRETESTATESPACE_DLG manages the user interface for TargetLink Discrete State Space block
%
% SYNTAX dlgInfo = TLDiscretestatespaceDlg('GetDlgInfo');
%   gets dialog info of TargetLink Discrete State Space block
%
%   INPUT ARGUMENTS
%   -/-
%
%   OUTPUT ARGUMENTS
%   dlgInfo     dialog information contains pageNames etc.
%
% SYNTAX [sheetDims, ctrlPos] = TLDiscretestatespaceDlg('CtrlPositions', pageName, commonGeom, dlgInfo, sheetDims);
%   calculates the control positions of all controls of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   commonGeom      common geometry data
%   dlgInfo         dialog information contains pageNames etc.
%   sheetDims       dimension of sheet
%
%   OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% SYNTAX dlgdata = TLDiscretestatespaceDlg('Create', pageName, dlgfig, dlgdata);
%   creates all controls of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   dlgfig          figure handle
%   dlgdata         dialog data
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%
% SYNTAX [dlgdata,bModified] = TLDiscretestatespaceDlg('Manage', pageName, dlgfig, dlgdata, pageAction);
%   manages all actions of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   dlgfig          figure handle
%   dlgdata         dialog data
%   pageAction      modified control of current page
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%   bModified       flag = 1, if dialog data are modified, =0 otherwise
%
% SYNTAX dlgdata = TLDiscretestatespaceDlg('Update', dlgfig, dlgdata, pageNum);
%   updates all controls of dialog page: <pageNum>
%
%   INPUT ARGUMENTS
%   dlgfig          figure handle
%   dlgdata         dialog data
%   pageNum         number of current page
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%
% SYNTAX TLDiscretestatespaceDlg('Apply', dlgfig, dlgdata);
%   writes current blockdata to block and DD
%
%   INPUT ARGUMENTS
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%
%   OUTPUT ARGUMENTS
%   - / -


% Author(s): D. Andoleit, T. Pietzsch
% $RCSfile: TLDiscretestatespaceDlg.m $
% $ProjectName: e:/ARC/Components/HostSW/SimulinkBlocksets/TLBlocksets/CommonBlockset/CommonBlockset_SimBlocksUI/Sources/MSrc/project.pj $
% $Revision: 1.28 $
% $Date: 2011/08/22 10:34:17MESZ $
%
% Copyright ?2011 dSPACE GmbH. All rights reserved.


switch action
    
    case 'GetDlgInfo'
        hBlock = varargin{1};
        dlgInfo = tl_get_dlginfodefaults('tlsim');
        titleName = 'Discrete State-Space';
        pathinfo = tl_pathinfo(hBlock);
        dlgInfo.title = sprintf('TargetLink %s: %s', titleName, pathinfo.shortDisplayName);
        dlgInfo.pageNames   = {
            'Output', ...
            'State', ...
            'Matrices', ...
            'Logging & Autoscaling', ...
            'Documentation'};
        varargout{1} = dlgInfo;
        varargout{2} = get_tlcg_data(hBlock);
        
    case 'CtrlPositions'
        pageName     = varargin{1};
        commonGeom   = varargin{2};
        sheetDims    = varargin{4};
        switch pageName
            case 'Output'
                [sheetDims, ctrlPos] = FcnCalcOutputCtrlPositions(commonGeom);
                
            case 'State'
                [sheetDims, ctrlPos] = FcnCalcStateCtrlPositions(commonGeom);
                
            case 'Matrices'
                [sheetDims, ctrlPos] = FcnCalcMatricesCtrlPositions(commonGeom);
                
            case 'Logging & Autoscaling'
                excludedCtrls = {};
                [sheetDims, ctrlPos] = ...
                    TLManageLoggingCtrls('calcCtrls', commonGeom, sheetDims, excludedCtrls);
                
            case 'Documentation'
                bTblBlock = 0;
                bCodeComment = 1;
                [sheetDims,ctrlPos] = TLManageDocCtrls( ...
                    'ctrlpos', commonGeom, sheetDims, bCodeComment, bTblBlock);
        end
        varargout{1} = sheetDims;
        varargout{2} = ctrlPos;
        
    case 'Create',
        pageName = varargin{1};
        dlgfig   = varargin{2};
        dlgdata  = varargin{3};
        pageNum  = strmatch(pageName, dlgdata.pageNames, 'exact');
        
        switch pageName
            case 'Output'
                dlgdata = FcnCreateOutputPage(pageNum, dlgfig, dlgdata);
                
            case 'State'
                dlgdata = FcnCreateStatePage(pageNum, dlgfig, dlgdata);
                
            case 'Matrices'
                dlgdata = FcnCreateMatricesPage(pageNum, dlgfig, dlgdata);
                
            case 'Logging & Autoscaling'
                dlgdata = TLManageLoggingCtrls('create',pageNum,dlgfig,dlgdata);
                
            case 'Documentation'
                dlgdata = TLManageDocCtrls('create',pageNum,dlgfig,dlgdata);
        end
        dlgdata.pageData{pageNum}.ctrlPos = [];
        
        % default values for user inputs in ss tool
        if ~isfield(dlgdata.pageData{1},'toolData')
            toolData = FcnGetDefaultToolData(dlgdata, 1);
            dlgdata.pageData{1}.toolData = toolData;
        end
        
        varargout{1} = dlgdata;
        
    case 'Manage',
        pageName   = varargin{1};
        dlgfig     = varargin{2};
        dlgdata    = varargin{3};
        pageAction = varargin{4};
        pageNum    = strmatch(pageName, dlgdata.pageNames, 'exact');
        
        switch pageName
            case 'Output'
                [dlgdata, bModified] = ...
                    FcnManageOutputPage(pageNum, dlgfig, dlgdata, pageAction);
                
            case 'State'
                [dlgdata, bModified] = ...
                    FcnManageStatePage(pageNum, dlgfig, dlgdata, pageAction);
                
            case 'Matrices'
                [dlgdata, bModified] = ...
                    FcnManageMatricesPage(pageNum, dlgfig, dlgdata, pageAction);
                
            case 'Logging & Autoscaling'
                [dlgdata, bModified] = ...
                    TLManageLoggingCtrls('manage', pageNum, dlgdata, pageAction, 'logdata');
                
            case 'Documentation'
                [dlgdata, bModified] = TLManageDocCtrls( ...
                    'callback', pageNum, dlgfig, dlgdata, pageAction);
        end
        varargout{1} = dlgdata;
        varargout{2} = bModified;
        
    case 'ManageSystemIcons',
        dlgfig     = varargin{1};
        dlgdata    = varargin{2};
        pageAction = varargin{3};
        [dlgdata, bModified] = FcnManageSystemIcons(dlgfig,dlgdata,pageAction);
        varargout{1} = dlgdata;
        varargout{2} = bModified;
        
    case 'Update'
        dlgfig      = varargin{1};
        dlgdata     = varargin{2};
        % update tool data from scaling tool
        if isstruct(varargin{3})
            dlgdata.pageData{1}.toolData = varargin{3};
            FcnCheckHeadroom(dlgdata);
            pageNum = dlgdata.CurrentPageNum;
        else
            pageNum = varargin{3};
        end
        switch pageNum
            case 1
                % Output page
                dlgdata = FcnUpdateOutputPage(dlgdata, dlgfig, pageNum);
            case 2
                % State page
                dlgdata = FcnUpdateStatePage(dlgdata, dlgfig, pageNum);
            case 3
                % Matrices
                dlgdata = FcnUpdateMatricesPage(dlgdata, dlgfig, pageNum);
            case 4
                % Logging page
                dlgdata =  FcnUpdataLoggingControls(pageNum, dlgfig, dlgdata);
            case 5
                % Documentation page
                TLManageDocCtrls('update', pageNum, dlgfig, dlgdata);
        end
        
        % get tool data for State-Space Scaling Tool
        toolData = FcnGetDefaultToolData(dlgdata,0);
        dlgdata.pageData{1}.toolData = toolData;
        
        if ishandle(dlgdata.toolfig)
            dlgdata = FcnUpdateSSTool(dlgdata);
        end
        
        varargout = {dlgdata};
        
    case 'Apply'
        dlgdata  = varargin{2};
        bContinue = varargin{3};    % =0 'apply', =1 'close'
        
        % set batchmode to avoid message boxes
        savedBatchMode = ds_error_get('batchmode');
        ds_error_set('BatchMode','on');
        [ok, msg, bErr] = FcnABCDCheck(dlgdata);
        ds_error_set('batchmode', savedBatchMode);
        if ~bErr
            msg = '';
        end
        [dlgdata, bContinue] = tl_apply_blockdata(dlgdata, bContinue, msg);
        varargout{1} = dlgdata;
        varargout{2} = bContinue;
        
    otherwise
        error(['Invalid action: "' action '"']);
end


%-----------------------------------------------------------------------------------------
% FcnManageSystemIcons manage actions of toolbar icons
%
% INPUT ARGUMENTS
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   action      action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-----------------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageSystemIcons(dlgfig, dlgdata, action) %#ok

bModified = false;
switch action
    case 'EditCode'
        % look for associated production code file
        [codefile,blockstr] = get_codefile(dlgdata.model);
        if ~isempty(codefile)
            codeedit(codefile,blockstr);
        end
        
    case 'ViewCode'
        switch dlgdata.pageNames{dlgdata.CurrentPageNum}
            case 'State'
                blockVar = 'state';
                tl_create_links_to_model('ShowComputation',dlgdata.model, blockVar);
            case 'Matrices'
                blockVar{1} = 'amatrix';
                blockVar{2} = 'bmatrix';
                blockVar{3} = 'cmatrix';
                blockVar{4} = 'dmatrix';
                idx = get(dlgdata.pageData{3}.children.selectPopup,'Value');
                tl_create_links_to_model('ShowDeclaration',dlgdata.model, blockVar{idx});
            otherwise
                blockVar = 'output';
                tl_create_links_to_model('ShowComputation',dlgdata.model, blockVar);
        end
        
    otherwise
        error('Invalid callback');
        
end % switch(action)


%-----------------------------------------------------------------------------------------
% FcnCalcOutputCtrlPositions calculates positions for all controls on output page
%
% INPUT ARGUMENTS
%   commonGeom      common geometrie information
%
% OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% HINT:
% Positions are calculated from the bottom left of the figure to avoid
% dependencies on figure size
%-----------------------------------------------------------------------------------------
function [sheetDims, ctrlPos] = FcnCalcOutputCtrlPositions(commonGeom)

% create standard output controls
excludedCtrls = {'inheritproperties'};
[sheetDims, ctrlPos, col, colDelta, rowDelta] = ...
    tl_calc_ctrls_positions(commonGeom, excludedCtrls);

% get sizes for further controls
strings_and_styles = {
    'Sample time:'         'text';
    ' State Space Tool ... ','pushbutton'};

[sampleTimeLabelSize, ...
    ssToolButtonSize] ...
    = ds_get_uicontrol_sizes(commonGeom,strings_and_styles);

%---------------------------------------
% enlarge groupbox
%---------------------------------------
% define new height for addoptGroupbox
ctrlPos.addoptGroupbox(4) = ...
    + 3 * commonGeom.editHeight ...
    + 2 * rowDelta ...
    + commonGeom.frameBottomEdgeBuffer ...
    + commonGeom.frameTopEdgeBuffer;

%---------------------------------------
% 3rd row
cy = commonGeom.frameBottomEdgeBuffer;

% statespace tool button
cx = col(1);
ctrlPos.ssToolButton = [cx cy ssToolButtonSize];
% sample time label
cx = col(4);
ctrlPos.sampleTimeLabel = [cx cy sampleTimeLabelSize];

% sample time edit field
cx = col(4) + col(2) - col(1);
ctrlPos.sampleTimeEdit = [cx cy ctrlPos.varEdit(3:4)];

%---------------------------------------
% 2nd row
cy = cy + commonGeom.editHeight + rowDelta;

% A matrix label
cx = col (1);
ctrlPos.aMatrixLabel = [cx cy ctrlPos.varLabel(3:4)];

% A matrix edit field
cx = col(2);
ctrlPos.aMatrixEdit = [cx cy ctrlPos.varEdit(3:4)];

% B matrix label
cx = col(4);
ctrlPos.bMatrixLabel = [cx cy ctrlPos.varLabel(3:4)];

% B matrix edit field
cx = col(4) + col(2) - col(1);
ctrlPos.bMatrixEdit = [cx cy ctrlPos.varEdit(3:4)];

%---------------------------------------
% 2nd row
cy = cy + commonGeom.editHeight + rowDelta;

% C matrix label
cx = col (1);
ctrlPos.cMatrixLabel = [cx cy ctrlPos.varLabel(3:4)];

% C matrix edit field
cx = col(2);
ctrlPos.cMatrixEdit = [cx cy ctrlPos.varEdit(3:4)];

% D matrix label
cx = col(4);
ctrlPos.dMatrixLabel = [cx cy ctrlPos.varLabel(3:4)];

% D matrix edit field
cx = col(4) + col(2) - col(1);
ctrlPos.dMatrixEdit = [cx cy ctrlPos.varEdit(3:4)];

% increase sheet dimensions
sheetDims(2) = sheetDims(2) ...
    + ctrlPos.addoptGroupbox(4);


%-----------------------------------------------------------------------------------------
% FcnCreateOutputPage creates the figure window
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%-----------------------------------------------------------------------------------------
function dlgdata = FcnCreateOutputPage(pageNum, dlgfig, dlgdata)

dlgdata = TLManageVariableCtrls('create', pageNum, dlgfig, dlgdata);
dlgdata = TLManageScalingCtrls('create', pageNum, dlgfig, dlgdata);

Children = dlgdata.pageData{pageNum}.children;
ctrlPos = dlgdata.pageData{pageNum}.ctrlPos;
pageName = dlgdata.pageNames{pageNum};
% create the addoptGroupbox which will contain state space options
Children.addoptGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'State Space options'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.addoptGroupbox);

% matrices value controls
Children.cMatrixLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'String',             'C:', ...
    'Style',              'text', ...
    'Position',           ctrlPos.cMatrixLabel);

Children.cMatrixEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'BackgroundColor',    'w', ...
    'Position',           ctrlPos.cMatrixEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''cMatrixEdit'')',pageName));

Children.dMatrixLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'String',             'D:', ...
    'Style',              'text', ...
    'Position',           ctrlPos.dMatrixLabel);

Children.dMatrixEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'BackgroundColor',    'w', ...
    'Position',           ctrlPos.dMatrixEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''dMatrixEdit'')',pageName));

Children.aMatrixLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'String',             'A:', ...
    'Style',              'text', ...
    'Position',           ctrlPos.aMatrixLabel);

Children.aMatrixEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'BackgroundColor',    'w', ...
    'Position',           ctrlPos.aMatrixEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''aMatrixEdit'')',pageName));

Children.bMatrixLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'String',             'B:', ...
    'Style',              'text', ...
    'Position',           ctrlPos.bMatrixLabel);

Children.bMatrixEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'BackgroundColor',    'w', ...
    'Position',           ctrlPos.bMatrixEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''bMatrixEdit'')',pageName));

% stepsize controls
Children.sampleTimeLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'text', ...
    'String',             'Sample time:', ...
    'Position',           ctrlPos.sampleTimeLabel);

Children.sampleTimeEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'String',             dlgdata.data.dt, ...
    'Position',           ctrlPos.sampleTimeEdit, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''sampleTimeEdit'')',pageName));

% state-space toolbutton
Children.ssToolButton = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             'State Space Tool ...', ...
    'Position',           ctrlPos.ssToolButton, ...
    'Callback',           sprintf('tldlg(''%s'',gcbf,''ssToolButton'')',pageName));

dlgdata.pageData{pageNum}.children = Children;


%-----------------------------------------------------------------------------------------
% FcnManageOutputPage manage control actions of output page
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   pageAction  action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-----------------------------------------------------------------------------------------
function [dlgdata,bModified] = FcnManageOutputPage(pageNum, dlgfig, dlgdata, pageAction)

bModified = false;
Children  = dlgdata.pageData{pageNum}.children;

switch pageAction
    case {'aMatrixEdit', 'bMatrixEdit', 'cMatrixEdit', 'dMatrixEdit'}
        propName = lower(pageAction(1:end-4));
        matrix = tl_deblank(get(Children.(pageAction), 'String'), 2);
        if ~isempty(matrix)
            if strcmp(matrix, 'ddv')
                if isempty(dlgdata.data.(propName).variable)
                    beep;
                else
                    dlgdata.data.(propName).value = ['ddv(''', dlgdata.data.(propName).variable, ''')'];
                    dlgdata.data.(propName).useddvariablevalue = true;
                end
            else
                dlgdata.data.(propName).value = matrix;
            end
        else
            beep;
        end
        bModified = true;
        
    case 'sampleTimeEdit'
        stepsizestr = get(Children.sampleTimeEdit, 'String');
        if ~isempty(stepsizestr)
            dlgdata.data.dt = stepsizestr;
        else
            beep;
        end
        bModified = true;
        
    case 'ssToolButton'
        if ishandle(dlgdata.toolfig)
            % existing tool dialog to foreground
            figure(dlgdata.toolfig);
        else
            [ok, msg] = FcnABCDCheck(dlgdata);
            if ok
                hdlgfig = get(dlgfig,'Parent');
                dlgdata.toolfig = dstabdlg('create', ...
                    'tl_sstool_dlg', dlgdata.model, 'State-Space Tool', hdlgfig);
                bModified = true;
            else
                ds_error_msg({'State-Space Scaling Tool cannot be opened:' msg}, ...
                    'Title', 'State-Space Scaling Tool', ...
                    'PrintMessage', 'no', ...
                    'RegisterMessage', 'no');
                bModified = false;
            end
        end
        
    otherwise
        [dlgdata, bModified1] = ...
            TLManageVariableCtrls('manage',pageNum,dlgfig,dlgdata,pageAction,'output');
        [dlgdata,bModified2] = ...
            TLManageScalingCtrls('manage',pageNum,dlgfig,dlgdata,pageAction,'output');
        bModified = bModified1 || bModified2;
        
end % switch pageAction


%--------------------------------------------------------------------------
% FcnUpdateOutputPage updates the controls of the output tab
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%   dlgfig      figure handle of dialog
%   pageNum     page Number
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%--------------------------------------------------------------------------
function dlgdata = FcnUpdateOutputPage(dlgdata, dlgfig, pageNum)

dlgdata = TLManageVariableCtrls('update', pageNum, dlgdata, 'output');
dlgdata = TLManageScalingCtrls('update', pageNum, dlgdata, 'output', []);

data = dlgdata.data;
sampleTimeEditCtrlStatus = struct('enable', 'on', 'string', data.dt); %#ok
ssToolButtonCtrlStatus = struct('enable', flag2str(dlgdata.bIsFullVs  ...
    & ~ds_isa(['/Pool/Typedefs/' data.output.type], 'constrainedtype') ...
    & ~ds_isa(['/Pool/Typedefs/' data.state.type], 'constrainedtype'))); %#ok

aMatrixEditCtrlStatus = struct('enable', 'on', 'string', dlgdata.data.amatrix.value); %#ok<NASGU>
bMatrixEditCtrlStatus = struct('enable', 'on', 'string', dlgdata.data.bmatrix.value); %#ok<NASGU>
cMatrixEditCtrlStatus = struct('enable', 'on', 'string', dlgdata.data.cmatrix.value); %#ok<NASGU>
dMatrixEditCtrlStatus = struct('enable', 'on', 'string', dlgdata.data.dmatrix.value); %#ok<NASGU>

Children = dlgdata.pageData{pageNum}.children;
ctrlsList = { ...
    'aMatrixEdit', ...
    'bMatrixEdit', ...
    'cMatrixEdit', ...
    'dMatrixEdit', ...
    'sampleTimeEdit', ...
    'ssToolButton'};
for ctrlsNo = 1:length(ctrlsList)
    ctrl = Children.(ctrlsList{ctrlsNo});
    UserData = get(ctrl, 'UserData');
    UserData.ctrlStatus = eval([ctrlsList{ctrlsNo} 'CtrlStatus']);
    set(ctrl, 'UserData', UserData);
end

TLManageVariableCtrls('setCtrls', pageNum, dlgfig, dlgdata);
TLManageScalingCtrls('setCtrls', pageNum, dlgfig, dlgdata);
TLSetCtrlsStatus(dlgfig, Children, ctrlsList)


%-----------------------------------------------------------------------------------------
% FcnCalcStateCtrlPositions calculates positions for all controls on state page
%
% INPUT ARGUMENTS
%   commonGeom      common geometrie information
%
% OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% HINT:
% Positions are calculated from the bottom left of the figure to avoid
% dependencies on figure size
%-----------------------------------------------------------------------------------------
function [sheetDims, ctrlPos] = FcnCalcStateCtrlPositions(commonGeom)

% calculate standard control positions
excludedCtrls = {'inheritproperties'};
[sheetDims, ctrlPos, col, colDelta, rowDelta] = ...
    tl_calc_ctrls_positions(commonGeom, excludedCtrls);

% determine sizes for additional controls
strings_and_styles = {'Initial condition:', 'text'; ...
    'Use value of Data Dictionary variable', 'checkbox'};
[initialValueLabelSize, useDDValueCheckboxSize] = ds_get_uicontrol_sizes(commonGeom, strings_and_styles);

origCol2 = col(2);
col(2) = col(1) + initialValueLabelSize(1) + colDelta / 3;
dx = col(2) - origCol2;
initialEditSize = [ctrlPos.varEdit(3) - dx, ctrlPos.varEdit(4)];

%-----------------------------------------------------------
% enlarge addoptGroupbox
%-----------------------------------------------------------
% define new height for addoptGroupbox
ctrlPos.addoptGroupbox(4) = commonGeom.editHeight ...
    + commonGeom.checkboxHeight ...
    + rowDelta ...
    + commonGeom.frameBottomEdgeBuffer ...
    + commonGeom.frameTopEdgeBuffer;

%---------------------------------------
% 2nd row
cy = + commonGeom.frameBottomEdgeBuffer;

% ddv checkbox
cx = col(2);
ctrlPos.useDDValueCheckbox = [cx, cy, useDDValueCheckboxSize];

%---------------------------------------
% 1st row
cy = cy + commonGeom.checkboxHeight + rowDelta;

% initial value label:
cx = col(1);
ctrlPos.initialValueLabel = [cx cy initialValueLabelSize];

% initial value edit field
cx = col(2);
ctrlPos.initialValueEdit = [cx cy initialEditSize];

% increase sheet dimensions
sheetDims(2) = sheetDims(2) + ...
    + ctrlPos.addoptGroupbox(4);


%-----------------------------------------------------------------------------------------
% FcnCreateStatePage creates the figure window
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%-----------------------------------------------------------------------------------------
function dlgdata = FcnCreateStatePage(pageNum, dlgfig, dlgdata)

dlgdata = TLManageVariableCtrls('create', pageNum, dlgfig, dlgdata);
dlgdata = TLManageScalingCtrls('create', pageNum, dlgfig, dlgdata);

Children = dlgdata.pageData{pageNum}.children;
ctrlPos = dlgdata.pageData{pageNum}.ctrlPos;

% create the addoptGroupbox which will contain initial condition
Children.addoptGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'Initial condition'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.addoptGroupbox);

% state initial value value controls
Children.initialValueLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'text', ...
    'String',             'Initial condition:', ...
    'Position',           ctrlPos.initialValueLabel);

Children.initialValueEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.initialValueEdit);

Children.useDDValueCheckbox = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'checkbox', ...
    'String',             'Use value of Data Dictionary variable', ...
    'Position',           ctrlPos.useDDValueCheckbox);

dlgdata.pageData{pageNum}.children  = Children;


%-----------------------------------------------------------------------------------------
% FcnManageStatePage manage control actions of state page
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   pageAction  action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-----------------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageStatePage(pageNum, dlgfig, dlgdata, pageAction)

Children = dlgdata.pageData{pageNum}.children;

switch pageAction
    case 'initialValueEdit'
        initialValueStr = deblank(get(Children.initialValueEdit, 'String'));
        if ~isempty(initialValueStr)
            if strcmp(initialValueStr, 'ddv')
                if isempty(dlgdata.data.state.variable)
                    beep;
                else
                    dlgdata.data.state.initial = ['ddv(''', dlgdata.data.state.variable, ''')'];
                    dlgdata.data.state.useddvariablevalue = true;
                end
            else
                dlgdata.data.state.initial = initialValueStr;
            end
        else
            beep;
        end
        bModified = true;
        
    case 'useDDValueCheckbox'
        if get(Children.useDDValueCheckbox, 'Value')
            dlgdata.data.state.initial = ['ddv(''', dlgdata.data.state.variable, ''')'];
            dlgdata.data.state.useddvariablevalue = true;
        else
            dlgdata.data.state.useddvariablevalue = false;
        end
        bModified = true;
        
    otherwise
        [dlgdata, bModified1] = TLManageVariableCtrls( ...
            'manage', pageNum, dlgfig, dlgdata, pageAction, 'state');
        [dlgdata, bModified2] = TLManageScalingCtrls( ...
            'manage', pageNum, dlgfig, dlgdata, pageAction, 'state');
        bModified = bModified1 | bModified2;
        
end % switch pageAction


%--------------------------------------------------------------------------
% FcnUpdateStatePage updates the controls of the state tab
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%   dlgfig      figure handle of dialog
%   pageNum     page Number
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%--------------------------------------------------------------------------
function dlgdata = FcnUpdateStatePage(dlgdata, dlgfig, pageNum)

if FcnIsMatrixGain(dlgdata)
    % deactivate all state controls if the block acts as a matrix gain, i.e. all
    % matrices except D are empty, so the transfer equation reduces to y = D*u.
    stateChildren = dlgdata.pageData{pageNum}.children;
    ctrlNames = fieldnames(stateChildren);
    userData.ctrlStatus.enable = 'off';
    structfun(@(c) (set(c,'UserData',userData)), stateChildren);
    TLSetCtrlsStatus(dlgfig, stateChildren, ctrlNames);
    return
end

Children = dlgdata.pageData{pageNum}.children;

% invoke standard update methods
dlgdata = TLManageVariableCtrls('update', pageNum, dlgdata, 'state');
[value, constraint, bCompliant] = tl_get_param_constraints( ...
    dlgdata.data.state, dlgdata.extdata.state, 'initial');
dlgdata = TLManageScalingCtrls('update', pageNum, dlgdata, 'state', constraint);

% initial value edit field status
initialValueEditCtrlStatus = struct('enable', 'on', 'string', dlgdata.data.state.initial);
if dlgdata.data.state.useddvariablevalue
    initialValueEditCtrlStatus.enable = 'inactive';
end
initialValueEditCtrlStatus.iserror = ~bCompliant;

% status of ddv checkbox
useDDValueCheckboxCtrlStatus.enable = flag2str(~isempty(dlgdata.data.state.variable));
useDDValueCheckboxCtrlStatus.value = dlgdata.data.state.useddvariablevalue;

% for states there are no simulated ranges.
simulatedLabelCtrlStatus = tl_get_control_userdata(Children.simulatedLabel);
upperSimulatedValueCtrlStatus = tl_get_control_userdata(Children.upperSimulatedValue);
lowerSimulatedValueCtrlStatus = tl_get_control_userdata(Children.lowerSimulatedValue);
simulatedLabelCtrlStatus.string = '';
upperSimulatedValueCtrlStatus.string = '';
lowerSimulatedValueCtrlStatus.string = '';

standardCtrlsList = {
    'simulatedLabel'...
    'upperSimulatedValue'...
    'lowerSimulatedValue'...
    };
ctrlsList = [{'initialValueEdit', 'useDDValueCheckbox'} standardCtrlsList];
for ctrlsNo = 1:length(ctrlsList)
    ctrl = Children.(ctrlsList{ctrlsNo});
    UserData = get(ctrl, 'UserData');
    UserData.ctrlStatus = eval([ctrlsList{ctrlsNo} 'CtrlStatus']);
    set(ctrl, 'UserData', UserData);
end

TLManageVariableCtrls('setCtrls', pageNum, dlgfig, dlgdata);
TLManageScalingCtrls('setCtrls', pageNum, dlgfig, dlgdata);
TLSetCtrlsStatus(dlgfig, Children, ctrlsList);


%-----------------------------------------------------------------------------------------
% FcnCalcMatricesCtrlPositions calculates positions for all controls on matrix page
%
% INPUT ARGUMENTS
%   commonGeom      common geometrie information
%
% OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% HINT:
% Positions are calculated from the bottom left of the figure to avoid
% dependencies on figure size
%-----------------------------------------------------------------------------------------
function [sheetDims, ctrlPos] = FcnCalcMatricesCtrlPositions(commonGeom)

% get sizes of standard controls
excludedCtrls = {'calcranges', 'saturate', 'inheritproperties'};
[sheetDims, ctrlPos, col, colDelta, rowDelta] = ...
    tl_calc_ctrls_positions(commonGeom, excludedCtrls);

strings_and_styles = {...
    'Select:',                  'text';
    '123 x 123',                'text';
    'Keep matrix structure',    'checkbox';
    ' Scale Matrix ',           'pushbutton';
    'Use value of Data Dictionary variable', 'checkbox'};

[selectLabelSize, ...
    sizeDisplaySize, ...
    matkeepCheckboxSize, ...
    autoscaleButtonSize, ...
    useDDValueCheckboxSize] = ...
    ds_get_uicontrol_sizes(commonGeom,strings_and_styles);

% calculate extra space needed for select popup
dy = commonGeom.editHeight + rowDelta;
% enlarge tlcgGroupbox and move addoptGroupbox
ctrlPos.tlcgoptGroupbox(4) = ctrlPos.tlcgoptGroupbox(4) + dy;
ctrlPos.addoptGroupbox(2)  = ctrlPos.addoptGroupbox(2)  + dy;

% define new height for addoptGroupbox
ctrlPos.addoptGroupbox(4) = 2 * commonGeom.editHeight ...
    + 2 * commonGeom.checkboxHeight ...
    + 3 * rowDelta ...
    + commonGeom.frameBottomEdgeBuffer ...
    + commonGeom.frameTopEdgeBuffer;

% supplement tlcgGroupbox
cy = ctrlPos.descLabel(2) + commonGeom.editHeight + rowDelta;

% select label
cx = col(1);
ctrlPos.selectLabel = [cx cy selectLabelSize];

% select popup
cx = col(2);
ctrlPos.selectPopup = [cx cy ctrlPos.lsbEdit(3:4)];

% size display field
cx = cx + ctrlPos.selectPopup(3) + colDelta;
ctrlPos.sizeDisplay = [cx cy sizeDisplaySize];

% keep matrix structure checkbox
cx = col(4);
ctrlPos.matkeepCheckbox = [cx cy matkeepCheckboxSize];

% scale matrix button
cx = col(7);
ctrlPos.scaleMatrixButton = [cx cy autoscaleButtonSize];

%---------------------------------------
% 4th row
cy = commonGeom.frameBottomEdgeBuffer;

cx = col(2);
ctrlPos.aMatrixDdvCheckbox = [cx, cy, useDDValueCheckboxSize];

cx = col(6);
ctrlPos.bMatrixDdvCheckbox = [cx, cy, useDDValueCheckboxSize];

%---------------------------------------
% 3rd row
cy = cy + commonGeom.checkboxHeight + rowDelta;

% A matrix label
cx = col (1);
ctrlPos.aMatrixLabel = [cx cy ctrlPos.varLabel(3:4)];

% A matrix edit field
cx = col(2);
ctrlPos.aMatrixEdit = [cx cy ctrlPos.varEdit(3:4)];

% B matrix label
cx = col(5);
ctrlPos.bMatrixLabel = [cx cy ctrlPos.varLabel(3:4)];

% B matrix edit field
cx = col(6);
ctrlPos.bMatrixEdit = [cx cy ctrlPos.varEdit(3:4)];

%---------------------------------------
% 2nd row
cy = cy + commonGeom.editHeight + rowDelta;

cx = col(2);
ctrlPos.cMatrixDdvCheckbox = [cx, cy, useDDValueCheckboxSize];

cx = col(6);
ctrlPos.dMatrixDdvCheckbox = [cx, cy, useDDValueCheckboxSize];

%---------------------------------------
% 1st row
cy = cy + commonGeom.checkboxHeight + rowDelta;

% C matrix label
cx = col (1);
ctrlPos.cMatrixLabel = [cx cy ctrlPos.varLabel(3:4)];

% C matrix edit field
cx = col(2);
ctrlPos.cMatrixEdit = [cx cy ctrlPos.varEdit(3:4)];

% D matrix label
cx = col(5);
ctrlPos.dMatrixLabel = [cx cy ctrlPos.varLabel(3:4)];

% D matrix edit field
cx = col(6);
ctrlPos.dMatrixEdit = [cx cy ctrlPos.varEdit(3:4)];

% increase sheet dimensions
sheetDims(2) = sheetDims(2) ...
    + ctrlPos.addoptGroupbox(4) ...
    + commonGeom.textHeight ...
    + dy;


%-----------------------------------------------------------------------------------------
% FcnCreateMatricesPage creates the figure window
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%-----------------------------------------------------------------------------------------
function dlgdata = FcnCreateMatricesPage(pageNum,dlgfig,dlgdata)

% remove width control positions, so no width controls are created
% (we just need the positions to put row/column controls in that place)
ctrlPos = dlgdata.pageData{pageNum}.ctrlPos;
pos.rowLabel = ctrlPos.widthLabel;
pos.rowEdit = ctrlPos.widthEdit;
pos.rowUpButton = ctrlPos.widthUpButton;
pos.rowDownButton = ctrlPos.widthDownButton;
pos.colLabel = ctrlPos.elementLabel;
pos.colEdit = ctrlPos.elementEdit;
pos.colUpButton = ctrlPos.elementUpButton;
pos.colDownButton = ctrlPos.elementDownButton;
ctrlPos = rmfield(ctrlPos, {'widthLabel', 'widthEdit', ...
    'widthUpButton', 'widthDownButton', ...
    'elementLabel', 'elementEdit', ...
    'elementUpButton', 'elementDownButton'});
dlgdata.pageData{pageNum}.ctrlPos = ctrlPos;

% create standard controls
dlgdata = TLManageVariableCtrls('create', pageNum, dlgfig, dlgdata);
dlgdata = TLManageScalingCtrls('create', pageNum, dlgfig, dlgdata);

% prepare some needed data
Children = dlgdata.pageData{pageNum}.children;
ctrlPos = dlgdata.pageData{pageNum}.ctrlPos;

% create the addoptGroupbox which will contain matrices options
Children.addoptGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'Matrices'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.addoptGroupbox);

% matrices value controls
Children.cMatrixLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'String',             'C:', ...
    'Style',              'text', ...
    'Position',           ctrlPos.cMatrixLabel);

Children.cMatrixEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'BackgroundColor',    'w', ...
    'Position',           ctrlPos.cMatrixEdit);

Children.cMatrixDdvCheckbox = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'checkbox', ...
    'String',             'Use value of Data Dictionary variable', ...
    'Position',           ctrlPos.cMatrixDdvCheckbox);

Children.dMatrixLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'String',             'D:', ...
    'Style',              'text', ...
    'Position',           ctrlPos.dMatrixLabel);

Children.dMatrixEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'BackgroundColor',    'w', ...
    'Position',           ctrlPos.dMatrixEdit);

Children.dMatrixDdvCheckbox = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'checkbox', ...
    'String',             'Use value of Data Dictionary variable', ...
    'Position',           ctrlPos.dMatrixDdvCheckbox);

Children.aMatrixLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'String',             'A:', ...
    'Style',              'text', ...
    'Position',           ctrlPos.aMatrixLabel);

Children.aMatrixEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'BackgroundColor',    'w', ...
    'Position',           ctrlPos.aMatrixEdit);

Children.aMatrixDdvCheckbox = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'checkbox', ...
    'String',             'Use value of Data Dictionary variable', ...
    'Position',           ctrlPos.aMatrixDdvCheckbox);

Children.bMatrixLabel = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'String',             'B:', ...
    'Style',              'text', ...
    'Position',           ctrlPos.bMatrixLabel);

Children.bMatrixEdit = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'edit', ...
    'BackgroundColor',    'w', ...
    'Position',           ctrlPos.bMatrixEdit);

Children.bMatrixDdvCheckbox = uicontrol( ...
    'Parent',             Children.addoptGroupbox, ...
    'Style',              'checkbox', ...
    'String',             'Use value of Data Dictionary variable', ...
    'Position',           ctrlPos.bMatrixDdvCheckbox);

% select controls
Children.selectLabel = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'String',             'Select:', ...
    'Style',              'text', ...
    'Position',           ctrlPos.selectLabel);

Children.selectPopup = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'Popupmenu', ...
    'String',             {'A', 'B', 'C', 'D'}, ...
    'Value',              1, ...
    'BackgroundColor',    'w', ...
    'Position',           ctrlPos.selectPopup);

% dimension display
Children.sizeDisplay = uicontrol(...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'text', ...
    'Position',           ctrlPos.sizeDisplay);

% keep current matrix structure checkbox
Children.matkeepCheckbox = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'checkbox', ...
    'String',             'Keep matrix structure', ...
    'Position',           ctrlPos.matkeepCheckbox);

% Matrices controls
Children.scaleMatrixButton = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             ' Scale Matrix ', ...
    'Position',           ctrlPos.scaleMatrixButton);

% row selection controls
Children.rowLabel = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'text', ...
    'String',             'Row:', ...
    'Position',           pos.rowLabel);
userData = struct('min', 1, 'max', Inf);
Children.rowEdit = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'Position',           pos.rowEdit, ...
    'UserData',           userData);

Children.rowUpButton = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             '+', ...
    'Position',           pos.rowUpButton);

Children.rowDownButton = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             '-', ...
    'Position',           pos.rowDownButton);

% column selection controls
Children.columnLabel = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'text', ...
    'String',             'Column:', ...
    'Position',           pos.colLabel);
userData = struct('min', 1, 'max', Inf);
Children.columnEdit = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'BackgroundColor',    'w', ...
    'Style',              'edit', ...
    'Position',           pos.colEdit, ...
    'UserData',           userData);

Children.columnUpButton = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             '+', ...
    'Position',           pos.colUpButton);

Children.columnDownButton = uicontrol( ...
    'Parent',             Children.tlcgoptGroupbox, ...
    'Style',              'pushbutton', ...
    'String',             '-', ...
    'Position',           pos.colDownButton);

dlgdata.pageData{pageNum}.children = Children;


%-----------------------------------------------------------------------------------------
% FcnManageMatricesPage manages control actions of matrix page
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   pageAction  action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-----------------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageMatricesPage(pageNum, dlgfig, dlgdata, pageAction)

Children = dlgdata.pageData{pageNum}.children;
vars = {'amatrix', 'bmatrix', 'cmatrix', 'dmatrix'};
selectIdx = get(Children.selectPopup, 'Value');
field = vars{selectIdx};

switch pageAction
    case 'matkeepCheckbox'
        dlgdata.data.matkeep = get(Children.matkeepCheckbox, 'Value');
        bModified = true;
        
    case {'aMatrixEdit', 'bMatrixEdit', 'cMatrixEdit', 'dMatrixEdit'}
        propName = lower(pageAction(1:end-4));
        matrix = tl_deblank(get(Children.(pageAction), 'String'), 2);
        if ~isempty(matrix)
            if strcmp(matrix, 'ddv')
                if isempty(dlgdata.data.(propName).variable)
                    beep;
                else
                    dlgdata.data.(propName).value = ['ddv(''', dlgdata.data.(propName).variable, ''')'];
                    dlgdata.data.(propName).useddvariablevalue = true;
                end
            else
                dlgdata.data.(propName).value = matrix;
            end
        else
            beep;
        end
        bModified = true;
        
    case {'aMatrixDdvCheckbox', 'bMatrixDdvCheckbox', 'cMatrixDdvCheckbox', 'dMatrixDdvCheckbox'}
        numChars = numel(pageAction) - numel('DdvCheckbox');
        propName = lower(pageAction(1:numChars));
        if get(Children.(pageAction), 'Value')
            dlgdata.data.(propName).value = ['ddv(''', dlgdata.data.(propName).variable, ''')'];
            dlgdata.data.(propName).useddvariablevalue = true;
        else
            dlgdata.data.(propName).useddvariablevalue = false;
        end
        bModified = true;
        
    case {'rowEdit', 'rowUpButton', 'rowDownButton'}
        % we can assume that the selected matrix has a known valid value and size
        % >= 1x1, otherwise the row controls would be deactivated
        matrix = tl_resolve(dlgdata.data.(field).value, dlgdata.model);
        userData = get(Children.rowEdit, 'UserData');
        if ~isempty(matrix)
            userData.max = size(matrix, 1);
        else
            userData.max = Inf;
        end
        set(Children.rowEdit, 'UserData', userData);
        row = dlgdata.extdata.(field).currentRowElement;
        [rowChar, bModified] = tl_handle_editupdown( 'Manage', ...
            num2str(row), ...
            [Children.rowEdit Children.rowUpButton Children.rowDownButton], ...
            Children.(pageAction));
        if ~isempty(str2num(rowChar)) && ~isequalwithequalnans(str2num(rowChar), NaN) %#ok<ST2NM>
            row = str2double(rowChar);
        end
        if bModified
            dlgdata.extdata.(field).currentRowElement = row;
            % calculate new current element
            col = dlgdata.extdata.(field).currentColElement;
            currentElement = dlgdata.data.(field).width(1) * (col-1) + row;
            dlgdata.extdata.(field).currentElement = currentElement;
        end
        
    case {'columnEdit', 'columnUpButton', 'columnDownButton'}
        % we can assume that the selected matrix has a known valid value and size
        % >= 1x1, otherwise the column controls would be deactivated
        matrix = tl_resolve(dlgdata.data.(field).value, dlgdata.model);
        userData = get(Children.columnEdit, 'UserData');
        if ~isempty(matrix)
            userData.max = size(matrix, 1);
        else
            userData.max = Inf;
        end
        set(Children.columnEdit, 'UserData', userData);
        col = dlgdata.extdata.(field).currentColElement;
        [colChar, bModified] = tl_handle_editupdown('Manage', ...
            num2str(col), ...
            [Children.columnEdit Children.columnUpButton Children.columnDownButton], ...
            Children.(pageAction));
        if ~isempty(str2num(colChar)) && ~isequalwithequalnans(str2num(colChar), NaN) %#ok<ST2NM>
            col = str2double(colChar);
        end
        if bModified
            dlgdata.extdata.(field).currentColElement = col;
            % calculate new current element
            row = dlgdata.extdata.(field).currentRowElement;
            currentElement = dlgdata.data.(field).width(1) * (col-1) + row;
            dlgdata.extdata.(field).currentElement = currentElement;
        end
        
    case 'selectPopup'
        bModified = true;
        
    case 'scaleMatrixButton'
        options.selectDatatypeSign = 'yes';
        options.minimizeWordWidth  = 'yes';
        ds_error_none;
        [dlgdata.data, bModified, msgstruct] = tl_scale_parameters( ...
            dlgdata.model, dlgdata.data, options, field);
        ds_error_register(msgstruct);
        ds_msgdlg('Update', ...
            'Title', ['Scaling of ' get_tlsubsystempath(dlgdata.model) '->' field], ...
            'ShowErrors','yes', ...
            'ShowNotes','yes', ...
            'ShowWarnings','yes');
        % tl_scale_parameters doesn't care about scalar expansion, so we switch
        % it off here (just like TL 2.2 did with the 'Same scaling' flag.)
        if dlgdata.data.(field).width ~= 1
            dlgdata.extdata.(field).scalarExp = 0;
        end
        
    otherwise
        [dlgdata, bModified1] = TLManageVariableCtrls( ...
            'manage', pageNum, dlgfig, dlgdata, pageAction, field);
        
        if bModified1 && any(strcmp(pageAction, {'classEdit', 'classSelectButton'}))
            % make sure all 4 matrices have the same variable class
            dlgdata.data.amatrix.class = dlgdata.data.(field).class;
            dlgdata.data.bmatrix.class = dlgdata.data.(field).class;
            dlgdata.data.cmatrix.class = dlgdata.data.(field).class;
            dlgdata.data.dmatrix.class = dlgdata.data.(field).class;
        end
        [dlgdata,bModified2] = TLManageScalingCtrls( ...
            'manage', pageNum, dlgfig, dlgdata, pageAction, field);
        bModified = bModified1 || bModified2;
        
end % switch pageAction


%--------------------------------------------------------------------------
% FcnUpdateMatricesPage updates the controls of the matrix tab
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%   dlgfig      figure handle of dialog
%   pageNum     page Number
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%--------------------------------------------------------------------------
function dlgdata = FcnUpdateMatricesPage(dlgdata, dlgfig, pageNum)

Children = dlgdata.pageData{pageNum}.children;

vars = {'amatrix', 'bmatrix', 'cmatrix', 'dmatrix'};
selectIdx = get(Children.selectPopup, 'Value');
field = vars{selectIdx};

% update/sync field: this will reshape the scaling data to row vectors, later we
% will restore them to matrix form
dlgdata = TLManageVariableCtrls('update', pageNum, dlgdata, field);

% show matrix size in the dialog if it is known
matrixValue = tl_resolve(dlgdata.data.(field).value, dlgdata.model);
if ~isempty(matrixValue)
    sizeDisplayCtrlStatus.string = sprintf('%d x %d', size(matrixValue,1), size(matrixValue,2));
end

% Current elements
if isfield(dlgdata.extdata.(field), 'currentRowElement') ...
        && ~isempty(dlgdata.extdata.(field).currentRowElement)
    currentRowElement = dlgdata.extdata.(field).currentRowElement;
    currentColElement = dlgdata.extdata.(field).currentColElement;
else
    currentRowElement = 1;
    currentColElement = 1;
    dlgdata.extdata.(field).currentRowElement = currentRowElement;
    dlgdata.extdata.(field).currentColElement = currentColElement;
end

% determine constraints for currently displayed field
if isempty(matrixValue)
    constraint = [];
elseif dlgdata.extdata.(field).scalarExp
    constraint = [min(min(matrixValue)) max(max(matrixValue))];
else
    constraint = matrixValue(currentRowElement,currentColElement);
end

dlgdata = TLManageScalingCtrls('update', pageNum, dlgdata, field, constraint);

% default control status
aMatrixEditCtrlStatus = struct('enable', 'on', 'string', dlgdata.data.amatrix.value);
bMatrixEditCtrlStatus = struct('enable', 'on', 'string', dlgdata.data.bmatrix.value);
cMatrixEditCtrlStatus = struct('enable', 'on', 'string', dlgdata.data.cmatrix.value);
dMatrixEditCtrlStatus = struct('enable', 'on', 'string', dlgdata.data.dmatrix.value);
sizeDisplayCtrlStatus = struct('enable', 'on', 'string', ''); %#ok<NASGU>
matkeepCheckboxCtrlStatus = struct('enable', 'on', 'value', dlgdata.data.matkeep);
scaleMatrixButtonCtrlStatus = struct('enable', 'on');   %#ok

% status of ddv checkbox
aMatrixDdvCheckboxCtrlStatus.enable = flag2str(~isempty(dlgdata.data.amatrix.variable));
aMatrixDdvCheckboxCtrlStatus.value = dlgdata.data.amatrix.useddvariablevalue;
if dlgdata.data.amatrix.useddvariablevalue
    aMatrixEditCtrlStatus.enable = 'inactive';
end
bMatrixDdvCheckboxCtrlStatus.enable = flag2str(~isempty(dlgdata.data.bmatrix.variable));
bMatrixDdvCheckboxCtrlStatus.value = dlgdata.data.bmatrix.useddvariablevalue;
if dlgdata.data.bmatrix.useddvariablevalue
    bMatrixEditCtrlStatus.enable = 'inactive';
end
cMatrixDdvCheckboxCtrlStatus.enable = flag2str(~isempty(dlgdata.data.cmatrix.variable));
cMatrixDdvCheckboxCtrlStatus.value = dlgdata.data.cmatrix.useddvariablevalue;
if dlgdata.data.cmatrix.useddvariablevalue
    cMatrixEditCtrlStatus.enable = 'inactive';
end
dMatrixDdvCheckboxCtrlStatus.enable = flag2str(~isempty(dlgdata.data.dmatrix.variable));
dMatrixDdvCheckboxCtrlStatus.value = dlgdata.data.dmatrix.useddvariablevalue;
if dlgdata.data.dmatrix.useddvariablevalue
    dMatrixEditCtrlStatus.enable = 'inactive';
end

% for parameters there are no simulated ranges. Instead, write min/max of gain value
simulatedLabelCtrlStatus = tl_get_control_userdata(Children.simulatedLabel);
upperSimulatedValueCtrlStatus = tl_get_control_userdata(Children.upperSimulatedValue);
lowerSimulatedValueCtrlStatus = tl_get_control_userdata(Children.lowerSimulatedValue);
if dlgdata.extdata.(field).scalarExp
    simulatedLabelCtrlStatus.string = 'of matrix';
else
    simulatedLabelCtrlStatus.string = 'of element';
end

rowEditCtrlStatus = struct('enable', 'on', 'string', '');
columnEditCtrlStatus = struct('enable', 'on', 'string', '');
rowUpButtonCtrlStatus = struct('enable', 'on');
rowDownButtonCtrlStatus = struct('enable', 'on');
columnUpButtonCtrlStatus = struct('enable', 'on');
columnDownButtonCtrlStatus = struct('enable', 'on');

% deactivate row/col controls if matrix is empty or could not be evaluated
if ~dlgdata.extdata.(field).scalarExp && ~strcmp(dlgdata.data.(field).value, '[]')
    if ~isequal(dlgdata.data.(field).width, -1)
        if numel(dlgdata.data.(field).width) == 1
            % width is scalar, but must be vectorized for matrix
            dlgdata.data.(field).width = [dlgdata.data.(field).width, 1];
        end
        if ~isequal(size(matrixValue), dlgdata.data.(field).width)
            % value field must be red coloured
            eval([field 'EditCtrlStatus.iserror = 1;']);
        end
    end
    
    rowEditCtrlStatus.string = currentRowElement;
    if (~isequal(dlgdata.data.(field).width, -1) && ~isempty(matrixValue) ...
            && currentRowElement >= dlgdata.data.(field).width(1)) ...
            || currentRowElement > 2^31 - 1
        rowUpButtonCtrlStatus.enable = 'off';
    end
    if currentRowElement <= 1
        rowDownButtonCtrlStatus.enable = 'off';
    end
    
    columnEditCtrlStatus.string = currentColElement;
    if (~isequal(dlgdata.data.(field).width, -1) && ~isempty(matrixValue) ...
            && currentColElement >= dlgdata.data.(field).width(2)) ...
            || currentColElement > 2^31-1
        columnUpButtonCtrlStatus.enable = 'off';
    end
    if currentColElement <= 1
        columnDownButtonCtrlStatus.enable = 'off';
    end
    
else
    rowEditCtrlStatus.enable = 'off';
    rowUpButtonCtrlStatus.enable = 'off';
    rowDownButtonCtrlStatus.enable = 'off';
    columnEditCtrlStatus.enable = 'off';
    columnUpButtonCtrlStatus.enable = 'off';
    columnDownButtonCtrlStatus.enable = 'off';
end

if ~strcmp(dlgdata.data.(field).class, 'default')
    % disable 'keep matrix structure' checkbox if variable class has
    % value_param or ref_param scope
    [bExist, hClass] = dsdd('Exist', ['/Pool/VariableClasses/', ...
        dlgdata.data.(field).class], 'ObjectKind', 'VariableClass');
    if bExist
        scope = dsdd('GetScope', hClass);
        bMatkeepEnable = ~any(strcmp({'value_param', 'ref_param'}, scope));
    else
        bMatkeepEnable = 0;
    end
    
    matkeepCheckboxCtrlStatus.enable = flag2str(bMatkeepEnable & dlgdata.bIsFullVs);
    matkeepCheckboxCtrlStatus.value = dlgdata.data.matkeep & bMatkeepEnable;
    
    if isempty(constraint)
        minstr = 'n.a.';
        maxstr = 'n.a.';
    else
        minstr = sprintf('%0.6g', min(constraint));
        maxstr = sprintf('%0.6g', max(constraint));
    end
    
    upperSimulatedValueCtrlStatus.string = maxstr;
    lowerSimulatedValueCtrlStatus.string = minstr;
else
    matkeepCheckboxCtrlStatus.enable = 'off';
    matkeepCheckboxCtrlStatus.value = 0;
end

extraCtrlsList = {
    'aMatrixEdit', ...
    'bMatrixEdit', ...
    'cMatrixEdit', ...
    'dMatrixEdit', ...
    'aMatrixDdvCheckbox', ...
    'bMatrixDdvCheckbox', ...
    'cMatrixDdvCheckbox', ...
    'dMatrixDdvCheckbox', ...
    'matkeepCheckbox', ...
    'sizeDisplay', ...
    'scaleMatrixButton', ...
    'rowEdit', ...
    'rowUpButton', ...
    'rowDownButton', ...
    'columnEdit', ...
    'columnUpButton', ...
    'columnDownButton', ...
    };
standardCtrlsList = {
    'simulatedLabel', ...
    'upperSimulatedValue', ...
    'lowerSimulatedValue'
    };
ctrlsList = [extraCtrlsList standardCtrlsList];
for ctrlsNo = 1:length(ctrlsList)
    ctrl = Children.(ctrlsList{ctrlsNo});
    UserData = get(ctrl, 'UserData');
    UserData.ctrlStatus = eval([ctrlsList{ctrlsNo} 'CtrlStatus']);
    set(ctrl, 'UserData', UserData);
end

% set control status of standard controls
TLManageVariableCtrls('setCtrls', pageNum, dlgfig, dlgdata);
TLManageScalingCtrls('setCtrls', pageNum, dlgfig, dlgdata);

% set status of Matrices controls
TLSetCtrlsStatus(dlgfig, Children, extraCtrlsList)


%-----------------------------------------------------------------------------------------
% FcnUpdataLoggingControls updates output page
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%   dlgfig      figure handle of dialog
%   pageNum     page Number
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%--------------------------------------------------------------------------
function dlgdata =  FcnUpdataLoggingControls(pageNum,dlgfig,dlgdata)

dlgdata =  TLManageLoggingCtrls('update',pageNum,dlgdata,'logdata','output');

Children = dlgdata.pageData{pageNum}.children;

% overwrite control status of offset
keepParamOffsetCheckboxCtrlStatus     = struct('enable', 'inactive', 'value', 1);   %#ok
ctrlsList = {'keepParamOffsetCheckbox'};
for ctrlsNo = 1:length(ctrlsList)
    ctrl = Children.(ctrlsList{ctrlsNo});
    UserData = get(ctrl, 'UserData');
    if strcmp(UserData.ctrlStatus.enable, 'on')
        UserData.ctrlStatus = eval([ctrlsList{ctrlsNo} 'CtrlStatus']);
        set(ctrl, 'UserData', UserData);
    end
end

TLManageLoggingCtrls('setCtrls',pageNum, dlgfig, dlgdata);


%--------------------------------------------------------------------------
% FcnIsMatrixGain determines whether we're really dealing with a matrix gain
% or a state space block
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   bMatrixGain     flag =1, if matrix gain, =0 otherwise
%--------------------------------------------------------------------------
function bMatrixGain = FcnIsMatrixGain(dlgdata)

bMatrixGain = ds_regexp('\[ *\]', dlgdata.data.amatrix.value);


%--------------------------------------------------------------------------
% FcnUpdateSSTool updates scaling tool
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%--------------------------------------------------------------------------
function dlgdata = FcnUpdateSSTool(dlgdata)

ok = true;

% check if type is one of TargetLink's basetypes
[bExist,hTypedef] = dsdd('Exist',['Pool/Typedefs/',dlgdata.data.output.type], ...
    'ObjectKind', 'Typedef');
if bExist,
    bIsBaseType = dsdd('GetIsBaseType',hTypedef);
else
    bIsBaseType = 0;
end

if ~FcnABCDCheck(dlgdata)
    errorStr = 'Block Data is inconsistent.';
    ok = false;
elseif ~bIsBaseType,
    errorStr = 'You have selected a non-basic datatype.';
    % state space scaling tool button
    set(dlgdata.pageData{1}.children.sstoolButton, ...
        'Enable','off');
    ok = false;
end
if ok
    tl_sstool_dlg('UpdateData',dlgdata.toolfig,dlgdata.data);
else
    ds_error_msg({errorStr 'The State-Space Scaling Tool will be closed.'}, ...
        'Title','State Space Scaling Tool', ...
        'PrintMessage','no', ...
        'RegisterMessage','no');
    if ishandle(dlgdata.toolfig),
        tooldlgdata = get(dlgdata.toolfig,'UserData');
        delete(dlgdata.toolfig);
        if ishandle(tooldlgdata.toolfig)
            delete(tooldlgdata.toolfig);
        end
        dlgdata.pageData{1}.toolData = tooldlgdata.toolData;
    else
        % the figure was deleted before quitting the error message box
        dlgdata.pageData{1}.toolData = FcnGetDefaultToolData(dlgdata);
    end
end


%--------------------------------------------------------------------------
% FcnABCDCheck check the consistency of dimensions of A,B,C,D
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   ok          flag is true, if data is consistent to open scaling tool, false otherwise
%   msg         error message
%   bErr        flag is true, if data should be corrected before apply, false otherwise
%--------------------------------------------------------------------------
function [ok, msg, bErr] = FcnABCDCheck(dlgdata)

ok = true;
msg = [];
bErr = false;

A = tl_resolve(dlgdata.data.amatrix.value, dlgdata.model);
B = tl_resolve(dlgdata.data.bmatrix.value, dlgdata.model);
C = tl_resolve(dlgdata.data.cmatrix.value, dlgdata.model);
D = tl_resolve(dlgdata.data.dmatrix.value, dlgdata.model);
% check the consistency of dimensions of A,B,C,D
errmsg = abcdchk(A,B,C,D);
if ~isempty(errmsg)
    msg = errmsg.message;
    ok = false;
    bErr = true;
end

if ~strcmp(dlgdata.data.amatrix.value, '[]') && isempty(A)
    msg = 'State-space matrix ''A'' could not be evaluated.';
    ok = false;
    return
end
if ~strcmp(dlgdata.data.bmatrix.value, '[]') && isempty(B)
    msg = 'State-space matrix ''B'' could not be evaluated.';
    ok = false;
    return
end
if ~strcmp(dlgdata.data.cmatrix.value, '[]') && isempty(C)
    msg = 'State-space matrix ''C'' could not be evaluated.';
    ok = false;
    return
end
if ~strcmp(dlgdata.data.dmatrix.value, '[]') && isempty(D)
    msg = 'State-space matrix ''D'' could not be evaluated.';
    ok = false;
    return
end
x0 = tl_resolve(dlgdata.data.state.initial, dlgdata.model);
if ~isempty(dlgdata.data.state.initial) && isempty(x0)
    msg = 'Initial condition could not be evaluated.';
    ok = false;
    return
end
if size(x0,1) ~= 1
    msg = 'Initial condition must be a row vector.';
    ok = false;
    bErr = true;
end


%--------------------------------------------------------------------------
% FcnGetDefaultToolData writes tool data into structure
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%   bDefault    flag =1 for default data, =0 otherwise
%
% OUTPUT ARGUMENTS
%   toolData     tool data
%--------------------------------------------------------------------------
function toolData = FcnGetDefaultToolData(dlgdata, bDefault)

Ad = tl_resolve(dlgdata.data.amatrix.value, dlgdata.model);
numInputs = size(Ad, 1);

if bDefault
    % retrieve toolData from block
    blockData = get_param(dlgdata.model,'UserData');
    if isfield(blockData,'toolData')
        toolData = blockData.toolData;
    else
        u_min = NaN * ones(1,numInputs);
        u_max = u_min;
        toolData.input.min = u_min;
        toolData.input.max = u_max;
        if FcnABCDCheck(dlgdata)
            convTol = min(cond(Ad) * 1e-7,1e-2);
        else
            convTol = 1e-2;
        end
        toolData.options.convTol = sprintf('%0.3g', convTol * 100);
        toolData.options.maxTime = '5';
        toolData.options.numRecs = '0';
        toolData.options.contNum = '0';
    end
else
    toolData  = dlgdata.pageData{1}.toolData;
    if numInputs ~= length(toolData.input.min)
        if length(toolData.input.min) > numInputs
            toolData.input.min = toolData.input.min(1:numInputs);
        elseif length(toolData.input.min) < numInputs
            toolData.input.min((end + 1):numInputs) = NaN;
        end
        if length(toolData.input.max) > numInputs
            toolData.input.max = toolData.input.max(1:numInputs);
        elseif length(toolData.input.max) < numInputs
            toolData.input.max((end + 1):numInputs) = NaN;
        end
    end
end


%--------------------------------------------------------------------------
% FcnCheckHeadroom checks headroom
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   - / -
%--------------------------------------------------------------------------
function FcnCheckHeadroom(dlgdata)

toolData    = dlgdata.pageData{1}.toolData;
minHeadRoom = 0.01;

numOutputs  = dlgdata.data.output.width;
constrRange = abs(dlgdata.data.output.max-dlgdata.data.output.min);
if  numOutputs && all(constrRange > 0)
    headroomMax = abs(toolData.output.max_impl-dlgdata.data.output.max)./constrRange;
    headroomMin = abs(toolData.output.min_impl-dlgdata.data.output.min)./constrRange;
    headRoomY   = min([headroomMax; headroomMin]);
    idxY        = find(headRoomY < minHeadRoom);
else
    idxY = [];
end

if ~isempty(idxY)
    str{1} = 'There may be overflows due to numerical';
    str{2} = 'effects if input signal is near to the limits !';
    str{3} = ' ';
    str{4} = 'The current scaling results in minimum';
    str{5} = 'headroom as follows:';
    str{6} = '      Variable:                  Headroom:';
    if length(idxY) > 3
        n = 3;
    else
        n = length(idxY);
    end
    for k = 1:n
        str{length(str)+1} = ['         y(' num2str(idxY(k)) ...
            ')           =>           ' ...
            sprintf('%0.4f',headRoomY(idxY(k))*100) ' %']; %#ok<AGROW>
    end
    if length(idxY) > 3
        str{length(str)+1} = '         .';
        str{length(str)+1} = '         .';
        str{length(str)+1} = '         .';
    end
    ds_error_msg(str, ...
        'Title','Transfer Function Scaling Tool', ...
        'PrintMessage','no', ...
        'RegisterMessage','no');
end
